﻿using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;

namespace PES_TurnierManager.Model
{
    /// <summary>
    /// A simple Group in this Tournament. Holds all players, who are
    /// Memebres of the Group and caluclates their rankings based on the
    /// matchresults
    /// </summary>
    public class Group
    {
        private Dictionary<string, HumanPlayer> mPlayers;
        private List<Match> mMatches;
        private Dictionary<uint, Match> mMatchesWithID;
        private string mGroupName;
        private bool mTwoLegs;
        private bool mHasGroupStarted;
        private uint mMatchIDCounter;
        private List<HumanPlayer> mRanking;

        public Group(string name)
        {
            mGroupName = name;
            mPlayers = new Dictionary<string,HumanPlayer>();
            mMatches = new List<Match>();
            mMatchesWithID = new Dictionary<uint, Match>();
            mMatchIDCounter = 0;
            mRanking = new List<HumanPlayer>();
            mTwoLegs = false;
            mHasGroupStarted = false;
        }

        public Group(string name, bool with2Legs)
        {
            mGroupName = name;
            mPlayers = new Dictionary<string, HumanPlayer>();
            mMatches = new List<Match>();
            mMatchesWithID = new Dictionary<uint, Match>();
            mMatchIDCounter = 0;
            mRanking = new List<HumanPlayer>();
            mTwoLegs = false;
            mHasGroupStarted = false;
            mTwoLegs = with2Legs;
        }

        public string getGroupName()
        {
            return mGroupName;
        }

        /// <summary>
        /// gets the player with the passed name 
        /// </summary>
        /// <param name="name">name of the player</param>
        /// <returns>the player</returns>
        public HumanPlayer getPlayer(string name)
        {
            return mPlayers[name];
        }

        /// <summary>
        /// Adds a new player to this group
        /// </summary>
        /// <param name="playerName">the name of the player</param>
        /// <param name="teamName">the name of the team used by the player</param>
        /// <returns>the created player</returns>
        public HumanPlayer addHumanPlayer(string playerName, string teamName)
        {
            HumanPlayer player = new HumanPlayer(playerName);
            player.setTeamName(teamName);

            mPlayers.Add(playerName, player);

            return player;
        }

        public bool hasGroupStarted()
        {
            return mHasGroupStarted;
        }


        public bool removePlayer(string playerName)
        {
            //check if the group has started yet
            if (!mHasGroupStarted)
            {
                if (mPlayers.ContainsKey(playerName))
                {
                    mPlayers.Remove(playerName);
                    return true;
                }
            }
            return false;
        }


        /// <summary>
        /// Checks if there is a player with the passed name
        /// </summary>
        /// <param name="playerName">name of the player</param>
        /// <returns>true if the player exists</returns>
        public bool existPlayer(string playerName)
        {
            return mPlayers.ContainsKey(playerName);
        }

        /// <summary>
        /// Generates all Matchups fpr this Group
        /// </summary>
        public List<Match> generateMatches()
        {
            HumanPlayer[] players = new HumanPlayer[mPlayers.Values.Count];
            mPlayers.Values.CopyTo(players, 0);
            for (int i = mPlayers.Values.Count - 1; i > 0; i--)
            {
                HumanPlayer homePlayer = players[i];
                for (int k = i-1; k >= 0; k--)
                {
                    //mMatches.Add(createMatch(players[i], players[k]));
                    mMatchesWithID.Add(mMatchIDCounter, createMatchWithID(players[i], players[k], mMatchIDCounter));

                    //Generate the same match with switched teams if we have 
                    //a groupphase with 2 Legs
                    if(mTwoLegs)
                        mMatchesWithID.Add(mMatchIDCounter, createMatchWithID(players[k], players[i], mMatchIDCounter));
                }
            }

            Match[] matchesList = new Match[mMatchesWithID.Count];
            mMatchesWithID.Values.CopyTo(matchesList, 0);
            List<Match> m = new List<Match>();
            foreach (Match match in matchesList)
            {
                m.Add(match);
            }

            return m;
        }

        public Match createMatch(HumanPlayer home, HumanPlayer guest)
        {
            return new Match(home, guest);
        }

        public Match createMatchWithID(HumanPlayer home, HumanPlayer guest, uint ID)
        {
            Match match = new Match(home, guest);
            match.setMatchID(mMatchIDCounter);
            mMatchIDCounter++;

            return match;
        }

        /// <summary>
        /// Calculates how many matches we have to play
        /// in this group
        /// </summary>
        /// <returns>the match count</returns>
        private int calculateMatchCount()
        {
            int result = 0;
            for (int i = mPlayers.Count; i > 0; i--)
            {
                result += i;
            }

            return result;
        }

        /// <summary>
        /// Add the result for a specific match
        /// </summary>
        /// <param name="matchID">ID of the match</param>
        /// <param name="homeScore">homescore</param>
        /// <param name="guestScore">guestscore</param>
        public void addMatchResult(uint matchID, uint homeScore, uint guestScore)
        {
            Match match = mMatchesWithID[matchID];
            match.setResult((uint)homeScore, (uint)guestScore);
            if (!mHasGroupStarted)
            {
                mHasGroupStarted = true;
            }
        }

        /// <summary>
        /// Calculates the ranking of the group
        /// </summary>
        private void updateRankings()
        {
            mRanking.Clear();
            mRanking = new List<HumanPlayer>(mPlayers.Values);
            mRanking.Sort();
        }
        
        /// <summary>
        /// Returns a list which represents the current
        /// ranking in the group. Player at index 0 ist 1st
        /// and so on
        /// </summary>
        /// <returns>list of players representing the ranking</returns>
        public List<HumanPlayer> getRanking()
        {
            updateRankings();
            return mRanking;
        }
    }
}
